﻿// Type: GandA.Component.Security.GandaMembershipProvider
// Assembly: GandA.Component.Security, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// Assembly location: C:\CodePlex\CLab\CLab\DLLs\GandA.Component.Security.dll

using System;
using System.Collections.Specialized;
using System.Configuration;
using System.Configuration.Provider;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Web.Security;

namespace GandA.Component.Security
{
    public class GandaMembershipProvider : MembershipProvider
    {
        private int newPasswordLength = 8;
        private string eventSource = "GandaMembershipProvider";
        private string eventLog = "Application";
        private string connectionString;
        private string pApplicationName;
        private bool pEnablePasswordReset;
        private bool pEnablePasswordRetrieval;
        private bool pRequiresQuestionAndAnswer;
        private bool pRequiresUniqueEmail;
        private int pMaxInvalidPasswordAttempts;
        private int pPasswordAttemptWindow;
        private MembershipPasswordFormat pPasswordFormat;
        private int pMinRequiredNonAlphanumericCharacters;
        private int pMinRequiredPasswordLength;
        private string pPasswordStrengthRegularExpression;
        private bool pWriteExceptionsToEventLog;
        private MachineKeySection machineKey;

        #region Propiedades

        public override string ApplicationName
        {
            get
            {
                return this.pApplicationName;
            }
            set
            {
                this.pApplicationName = value;
            }
        }

        public override bool EnablePasswordReset
        {
            get
            {
                return this.pEnablePasswordReset;
            }
        }

        public override bool EnablePasswordRetrieval
        {
            get
            {
                return this.pEnablePasswordRetrieval;
            }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get
            {
                return this.pRequiresQuestionAndAnswer;
            }
        }

        public override bool RequiresUniqueEmail
        {
            get
            {
                return this.pRequiresUniqueEmail;
            }
        }

        public override int MaxInvalidPasswordAttempts
        {
            get
            {
                return this.pMaxInvalidPasswordAttempts;
            }
        }

        public override int PasswordAttemptWindow
        {
            get
            {
                return this.pPasswordAttemptWindow;
            }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get
            {
                return this.pPasswordFormat;
            }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get
            {
                return this.pMinRequiredNonAlphanumericCharacters;
            }
        }

        public override int MinRequiredPasswordLength
        {
            get
            {
                return this.pMinRequiredPasswordLength;
            }
        }

        public override string PasswordStrengthRegularExpression
        {
            get
            {
                return this.pPasswordStrengthRegularExpression;
            }
        }

        public bool WriteExceptionsToEventLog
        {
            get
            {
                return this.pWriteExceptionsToEventLog;
            }
            set
            {
                this.pWriteExceptionsToEventLog = value;
            }
        }

        #endregion

        public override void Initialize(string name, NameValueCollection config)
        {
            if (config == null)
                throw new ArgumentNullException("config");
            if (name == null || name.Length == 0)
                name = "AspNetGandaMembershipProvider";
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "Seguridad GandA Membership provider");
            }
            base.Initialize(name, config);
            this.pApplicationName = this.GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath);
            this.pMaxInvalidPasswordAttempts = Convert.ToInt32(this.GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
            this.pPasswordAttemptWindow = Convert.ToInt32(this.GetConfigValue(config["passwordAttemptWindow"], "10"));
            this.pMinRequiredNonAlphanumericCharacters = Convert.ToInt32(this.GetConfigValue(config["minRequiredNonAlphanumericCharacters"], "1"));
            this.pMinRequiredPasswordLength = Convert.ToInt32(this.GetConfigValue(config["minRequiredPasswordLength"], "7"));
            this.pPasswordStrengthRegularExpression = Convert.ToString(this.GetConfigValue(config["passwordStrengthRegularExpression"], ""));
            this.pEnablePasswordReset = Convert.ToBoolean(this.GetConfigValue(config["enablePasswordReset"], "true"));
            this.pEnablePasswordRetrieval = Convert.ToBoolean(this.GetConfigValue(config["enablePasswordRetrieval"], "true"));
            this.pRequiresQuestionAndAnswer = Convert.ToBoolean(this.GetConfigValue(config["requiresQuestionAndAnswer"], "false"));
            this.pRequiresUniqueEmail = Convert.ToBoolean(this.GetConfigValue(config["requiresUniqueEmail"], "true"));
            this.pWriteExceptionsToEventLog = Convert.ToBoolean(this.GetConfigValue(config["writeExceptionsToEventLog"], "true"));
            switch (config["passwordFormat"] ?? "Hashed")
            {
                case "Hashed":
                    this.pPasswordFormat = MembershipPasswordFormat.Hashed;
                    break;
                case "Encrypted":
                    this.pPasswordFormat = MembershipPasswordFormat.Encrypted;
                    break;
                case "Clear":
                    this.pPasswordFormat = MembershipPasswordFormat.Clear;
                    break;
                default:
                    throw new ProviderException("Password format not supported.");
            }
            ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings[config["connectionStringName"]];
            if (connectionStringSettings == null || connectionStringSettings.ConnectionString.Trim() == "")
                throw new ProviderException("Connection string cannot be blank.");
            this.connectionString = connectionStringSettings.ConnectionString;
            this.machineKey = (MachineKeySection)WebConfigurationManager.OpenWebConfiguration(HostingEnvironment.ApplicationVirtualPath).GetSection("system.web/machineKey");
            if (this.machineKey.ValidationKey.Contains("AutoGenerate") && this.PasswordFormat != MembershipPasswordFormat.Clear)
                throw new ProviderException("Hashed or Encrypted passwords are not supported with auto-generated keys.");
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            throw new NotImplementedException();
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new NotImplementedException();
        }

        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            throw new NotImplementedException();
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }

        public override int GetNumberOfUsersOnline()
        {
            throw new NotImplementedException();
        }

        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            throw new NotImplementedException();
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            throw new NotImplementedException();
        }

        public override string GetUserNameByEmail(string email)
        {
            throw new NotImplementedException();
        }

        public override string ResetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }

        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }

        public override void UpdateUser(MembershipUser user)
        {
            throw new NotImplementedException();
        }

        public override bool ValidateUser(string username, string password)
        {
            bool flag = false;
            SqlConnection connection = new SqlConnection(this.connectionString);
            SqlCommand sqlCommand = new SqlCommand("security.spValidaUsuario", connection);
            sqlCommand.CommandType = CommandType.StoredProcedure;
            sqlCommand.Parameters.Add("@psUserName", SqlDbType.VarChar, 20).Value = (object)username;
            sqlCommand.Parameters.Add("@psPassword", SqlDbType.VarChar, 200).Value = (object)password;
            SqlDataAdapter sqlDataAdapter = new SqlDataAdapter();
            DataSet dataSet = new DataSet();
            try
            {
                connection.Open();
                sqlDataAdapter.SelectCommand = sqlCommand;
                ((DataAdapter)sqlDataAdapter).Fill(dataSet);
                if (dataSet.Tables.Count > 0)
                    flag = dataSet.Tables[0].Rows[0]["TienePermiso"].ToString() == "1";
            }
            catch (Exception ex)
            {
                throw new ProviderException(ex.Message);
            }
            finally
            {
                if (connection.State == ConnectionState.Open)
                    connection.Close();
                connection.Dispose();
                dataSet.Dispose();
            }
            return flag;
        }

        private string GetConfigValue(string configValue, string defaultValue)
        {
            if (string.IsNullOrEmpty(configValue))
                return defaultValue;
            else
                return configValue;
        }

        private bool CheckPassword(string password, string dbpassword)
        {
            string str1 = password;
            string str2 = dbpassword;
            switch (this.PasswordFormat)
            {
                case MembershipPasswordFormat.Hashed:
                    str1 = this.EncodePassword(password);
                    break;
                case MembershipPasswordFormat.Encrypted:
                    str2 = this.UnEncodePassword(dbpassword);
                    break;
            }
            return str1 == str2;
        }

        private string UnEncodePassword(string encodedPassword)
        {
            string s = encodedPassword;
            switch (this.PasswordFormat)
            {
                case MembershipPasswordFormat.Clear:
                    return s;
                case MembershipPasswordFormat.Hashed:
                    throw new ProviderException("Cannot unencode a hashed password.");
                case MembershipPasswordFormat.Encrypted:
                    s = Encoding.Unicode.GetString(this.DecryptPassword(Convert.FromBase64String(s)));
                    goto case 0;
                default:
                    throw new ProviderException("Unsupported password format.");
            }
        }

        private string EncodePassword(string password)
        {
            string str = password;
            switch (this.PasswordFormat)
            {
                case MembershipPasswordFormat.Clear:
                    return str;
                case MembershipPasswordFormat.Hashed:
                    HMACSHA1 hmacshA1 = new HMACSHA1();
                    hmacshA1.Key = this.HexToByte(this.machineKey.ValidationKey);
                    str = Convert.ToBase64String(hmacshA1.ComputeHash(Encoding.Unicode.GetBytes(password)));
                    goto case 0;
                case MembershipPasswordFormat.Encrypted:
                    str = Convert.ToBase64String(this.EncryptPassword(Encoding.Unicode.GetBytes(password)));
                    goto case 0;
                default:
                    throw new ProviderException("Unsupported password format.");
            }
        }

        private byte[] HexToByte(string hexString)
        {
            byte[] numArray = new byte[hexString.Length / 2];
            for (int index = 0; index < numArray.Length; ++index)
                numArray[index] = Convert.ToByte(hexString.Substring(index * 2, 2), 16);
            return numArray;
        }

        private void WriteToEventLog(Exception e, string action)
        {
            EventLog eventLog = new EventLog();
            eventLog.Source = this.eventSource;
            eventLog.Log = this.eventLog;
            string message = "An exception occurred communicating with the data source.\n\n" + "Action: " + action + "\n\n" + "Exception: " + ((object)e).ToString();
            eventLog.WriteEntry(message);
        }
    }
}
